Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ lint:
black src

test-poetry:
poetry run pytest -s -v --cov=src --cov-report=term-missing --cov-fail-under=83 --cov-report=html
poetry run pytest -s -v --cov=src --cov-report=term-missing --cov-fail-under=82 --cov-report=html

test:
pytest -s -v --cov=src --cov-report=term-missing --cov-fail-under=83 --cov-report=html
pytest -s -v --cov=src --cov-report=term-missing --cov-fail-under=82 --cov-report=html
2 changes: 1 addition & 1 deletion rag-metrics.py
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@
)

from src.app.shared.utils.dependencies import get_settings
from src.app.services.abst_chat import AbstractChat
from src.app.shared.infra.abst_chat import AbstractChat

logger = logging.getLogger(__name__)

Expand Down
12 changes: 3 additions & 9 deletions src/app/api/api_v1/api.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,19 +2,13 @@

from fastapi import APIRouter

from src.app.api.api_v1.endpoints import (
chat,
metric,
micro_learning,
search,
tutor,
user,
)
from src.app.api.api_v1.endpoints import chat, metric, micro_learning, search, user
from src.app.tutor.api import router

api_router = APIRouter()
api_router.include_router(chat.router, prefix="/qna", tags=["qna"])
api_router.include_router(search.router, prefix="/search", tags=["search"])
api_router.include_router(tutor.router, prefix="/tutor", tags=["tutor"])
api_router.include_router(router.router, prefix="/tutor", tags=["tutor"])
api_router.include_router(metric.router, prefix="/metric", tags=["metric"])
api_router.include_router(
micro_learning.router, prefix="/micro_learning", tags=["micro_learning"]
Expand Down
4 changes: 2 additions & 2 deletions src/app/api/api_v1/endpoints/chat.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,9 +11,7 @@
from psycopg.rows import dict_row
from pydantic import BaseModel

from src.app.shared.utils.dependencies import get_settings
from src.app.models import chat as models
from src.app.services.abst_chat import get_chat_service
from src.app.services.constants import subjects as subjectsDict
from src.app.services.data_collection import get_data_collection_service
from src.app.services.exceptions import (
Expand All @@ -23,6 +21,8 @@
bad_request,
)
from src.app.services.search import SearchService, get_search_service
from src.app.shared.infra.abst_chat import get_chat_service
from src.app.shared.utils.dependencies import get_settings
from src.app.utils.logger import logger as utils_logger

logger = utils_logger(__name__)
Expand Down
2 changes: 1 addition & 1 deletion src/app/api/api_v1/endpoints/metric.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,10 @@
from pydantic import ValidationError
from starlette.concurrency import run_in_threadpool

from src.app.shared.utils.dependencies import get_settings
from src.app.models.metric import DocumentClickUpdateResponse, RowCorpusQtyDocInfo
from src.app.services.data_collection import get_data_collection_service
from src.app.services.sql_db.queries import get_document_qty_table_info_sync
from src.app.shared.utils.dependencies import get_settings
from src.app.utils.logger import logger as utils_logger

logger = utils_logger(__name__)
Expand Down
5 changes: 4 additions & 1 deletion src/app/core/lifespan.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,13 +5,15 @@
from fastapi import FastAPI
from qdrant_client import AsyncQdrantClient

from src.app.shared.infra.llm_proxy import LLMProxy
from src.app.shared.utils.dependencies import get_settings
from src.app.services.llm_proxy import LLMProxy
from src.app.tutor.service.tutor import close_chat_model, init_chat_model


@asynccontextmanager
async def lifespan(app: FastAPI):
settings = get_settings()
await init_chat_model(settings)
app.state.qdrant = AsyncQdrantClient(
url=settings.QDRANT_HOST,
port=settings.QDRANT_PORT,
Expand All @@ -28,3 +30,4 @@ async def lifespan(app: FastAPI):
yield
await app.state.qdrant.close()
await app.state.llm.close_client()
await close_chat_model()
4 changes: 2 additions & 2 deletions src/app/services/data_collection.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,6 @@
from fastapi.concurrency import run_in_threadpool
from qdrant_client.models import ScoredPoint

from src.app.shared.utils.dependencies import get_settings
from src.app.models.documents import Document
from src.app.services.sql_db.queries import (
get_current_data_collection_campaign,
Expand All @@ -22,7 +21,8 @@
write_user_query,
)
from src.app.services.sql_db.queries_user import get_user_from_session_id
from src.app.services.tutor.models import SyllabusFeedback, TutorSyllabusRequest
from src.app.shared.utils.dependencies import get_settings
from src.app.tutor.service.models import SyllabusFeedback, TutorSyllabusRequest
from src.app.utils.logger import logger as utils_logger

logger = utils_logger(__name__)
Expand Down
File renamed without changes.
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,6 @@
from langgraph.checkpoint.postgres.aio import AsyncPostgresSaver # type: ignore
from langgraph.prebuilt import create_react_agent # type: ignore

from src.app.shared.utils.dependencies import get_settings
from src.app.models.chat import ReformulatedQueryResponse
from src.app.models.documents import Document
from src.app.services import prompts
Expand All @@ -41,8 +40,9 @@
stringify_docs_content,
)

# from src.app.services.llm_proxy import LLMProxy
# from src.app.shared.infra.llm_proxy import LLMProxy
from src.app.services.search import SearchService
from src.app.shared.utils.dependencies import get_settings
from src.app.utils.decorators import log_time_and_error
from src.app.utils.logger import log_environmental_impacts
from src.app.utils.logger import logger as utils_logger
Expand Down Expand Up @@ -85,7 +85,6 @@ def __init__(

@log_time_and_error
async def json_formatter_agent(self, unformatted_input, expected_output):
print(unformatted_input)
output = await self.chat_client.completion(
messages=[
{
Expand Down
File renamed without changes.
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,8 @@
from pypdf import PdfReader
from qdrant_client.models import ScoredPoint

from src.app.shared.infra.pdf_extractor import extract_txt_from_pdf_with_tika
from src.app.shared.utils.dependencies import get_settings
from src.app.services.pdf_extractor import extract_txt_from_pdf_with_tika
from src.app.utils.decorators import log_time_and_error_sync

settings = get_settings()
Expand Down
16 changes: 8 additions & 8 deletions src/app/tests/api/api_v1/test_chat.py
Original file line number Diff line number Diff line change
Expand Up @@ -69,9 +69,9 @@
new=mock.MagicMock(return_value=True),
)
@mock.patch(
"src.app.services.abst_chat.AbstractChat._detect_language",
"src.app.shared.infra.abst_chat.AbstractChat._detect_language",
)
@mock.patch("src.app.services.abst_chat.AbstractChat.chat_message")
@mock.patch("src.app.shared.infra.abst_chat.AbstractChat.chat_message")
class QnATests(unittest.IsolatedAsyncioTestCase):
def setUp(self):
backoff.on_exception = MagicMock()
Expand Down Expand Up @@ -146,7 +146,7 @@ async def test_chat_not_supported_lang(self, chat_mock, *mocks):

async def test_chat_rephrase(self, *mocks):
with mock.patch(
"src.app.services.abst_chat.AbstractChat.rephrase_message",
"src.app.shared.infra.abst_chat.AbstractChat.rephrase_message",
return_value="ok",
) as mock_rephrase:

Expand Down Expand Up @@ -214,7 +214,7 @@ async def test_new_questions_ok(
self, mock_db_session, mock_chat_completion, mock__detect_language
):
with mock.patch(
"src.app.services.abst_chat.AbstractChat.get_new_questions",
"src.app.shared.infra.abst_chat.AbstractChat.get_new_questions",
return_value={"NEW_QUESTIONS": ["Your reformulated question"]},
) as new_questions_mock:
mock__detect_language.return_value = {"ISO_CODE": "en"}
Expand Down Expand Up @@ -255,10 +255,10 @@ async def test_reformulate_ok(
self, mock_db_session, mock_chat_completion, mock__detect_language
):
with mock.patch(
"src.app.services.abst_chat.AbstractChat._detect_past_message_ref",
"src.app.shared.infra.abst_chat.AbstractChat._detect_past_message_ref",
return_value={"REF_TO_PAST": "false", "CONFIDENCE": "0.9"},
), mock.patch(
"src.app.services.abst_chat.AbstractChat.reformulate_user_query",
"src.app.shared.infra.abst_chat.AbstractChat.reformulate_user_query",
return_value=ReformulatedQueryResponse(
STANDALONE_QUESTION_EN="Your reformulated question",
STANDALONE_QUESTION_FR="Votre question reformulée",
Expand Down Expand Up @@ -286,7 +286,7 @@ async def test_reformulate_ok(

async def test_stream(self, *mocks):
with mock.patch(
"src.app.services.abst_chat.AbstractChat.chat_message",
"src.app.shared.infra.abst_chat.AbstractChat.chat_message",
) as stream_mock:

with TestClient(app) as client:
Expand Down Expand Up @@ -334,7 +334,7 @@ async def test_stream(self, *mocks):
"src.app.services.security.check_api_key_sync",
new=mock.MagicMock(return_value=True),
)
@mock.patch("src.app.services.abst_chat.AbstractChat.agent_message")
@mock.patch("src.app.shared.infra.abst_chat.AbstractChat.agent_message")
def test_chat_agent(self, agent_message_mock, *mocks):
agent_message_mock.return_value = {
"messages": [
Expand Down
10 changes: 5 additions & 5 deletions src/app/tests/services/test_abst_chat.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,16 +2,16 @@
from unittest import mock

from src.app.models.chat import ReformulatedQueryResponse
from src.app.services.abst_chat import AbstractChat
from src.app.services.exceptions import LanguageNotSupportedError
from src.app.shared.infra.abst_chat import AbstractChat


class TestAbstractChat(unittest.IsolatedAsyncioTestCase):
def setUp(self):
mocked_client = mock.AsyncMock()
self.chat = AbstractChat(client=mocked_client)

@mock.patch("src.app.services.abst_chat.detect_language_from_entry")
@mock.patch("src.app.shared.infra.abst_chat.detect_language_from_entry")
async def test_lang_error_helper(self, mock_detect_lang):
self.chat._detect_lang_with_llm = mock.AsyncMock()

Expand All @@ -20,14 +20,14 @@ async def test_lang_error_helper(self, mock_detect_lang):
self.chat._detect_lang_with_llm.assert_called_once()

@mock.patch(
"src.app.services.abst_chat.detect_language_from_entry", return_value="en"
"src.app.shared.infra.abst_chat.detect_language_from_entry", return_value="en"
)
async def test_lang_ok(self, mock_detect_lang):
lang = await self.chat._detect_language("fake message")
assert lang == {"ISO_CODE": "en"}

@mock.patch(
"src.app.services.abst_chat.detect_language_from_entry",
"src.app.shared.infra.abst_chat.detect_language_from_entry",
side_effect=LanguageNotSupportedError,
)
async def test_lang_not_supported(self, mock_detect_lang):
Expand All @@ -40,7 +40,7 @@ async def test_lang_not_supported(self, mock_detect_lang):
await self.chat._detect_language("fake message")

@mock.patch(
"src.app.services.abst_chat.detect_language_from_entry",
"src.app.shared.infra.abst_chat.detect_language_from_entry",
side_effect=LanguageNotSupportedError,
)
async def test_lang_supported(self, mock_detect_lang):
Expand Down
2 changes: 1 addition & 1 deletion src/app/tests/services/test_data_collection.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
from fastapi import HTTPException

from src.app.services.data_collection import DataCollection, _cache
from src.app.services.tutor.models import ExtractorOutput, TutorSyllabusRequest
from src.app.tutor.service.models import ExtractorOutput, TutorSyllabusRequest


async def fake_run_in_threadpool(func, *args, **kwargs):
Expand Down
4 changes: 2 additions & 2 deletions src/app/tests/services/test_llm_proxy.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@

from litellm.types.utils import Choices, Message, ModelResponse

from src.app.services.llm_proxy import LLMProxy
from src.app.shared.infra.llm_proxy import LLMProxy


def create_chat_responses_mocks(response: str):
Expand All @@ -16,7 +16,7 @@ def create_chat_responses_mocks(response: str):
)


@mock.patch("src.app.services.llm_proxy.acompletion", new_callable=mock.AsyncMock)
@mock.patch("src.app.shared.infra.llm_proxy.acompletion", new_callable=mock.AsyncMock)
class TestLLMProxy(unittest.IsolatedAsyncioTestCase):
def setUp(self):
self.proxy = LLMProxy(model="fake_model")
Expand Down
12 changes: 7 additions & 5 deletions src/app/tests/services/test_pdf_extractor.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,8 @@
import unittest
from unittest.mock import AsyncMock, Mock, patch

from src.app.services import pdf_extractor
from src.app.services.pdf_extractor import (
from src.app.shared.infra import pdf_extractor
from src.app.shared.infra.pdf_extractor import (
_parse_tika_content,
_send_pdf_to_tika,
extract_txt_from_pdf_with_tika,
Expand All @@ -28,7 +28,7 @@ def test_remove_hyphens(self):


class TestPDFExtractorAsync(unittest.IsolatedAsyncioTestCase):
@patch("src.app.services.pdf_extractor.get_new_https_async_client")
@patch("src.app.shared.infra.pdf_extractor.get_new_https_async_client")
async def test_send_pdf_to_tika(self, mock_get_client):
# Mock du client HTTPX asynchrone
mock_client = AsyncMock()
Expand Down Expand Up @@ -69,8 +69,10 @@ def test_parse_tika_content(self):
expected_result = [["Page 1 content"], ["Page 2 content"]]
self.assertEqual(result, expected_result)

@patch("src.app.services.pdf_extractor._send_pdf_to_tika", new_callable=AsyncMock)
@patch("src.app.services.pdf_extractor._parse_tika_content")
@patch(
"src.app.shared.infra.pdf_extractor._send_pdf_to_tika", new_callable=AsyncMock
)
@patch("src.app.shared.infra.pdf_extractor._parse_tika_content")
async def test_extract_txt_from_pdf_with_tika(
self, mock_parse_tika_content, mock_send_pdf_to_tika
):
Expand Down
2 changes: 1 addition & 1 deletion src/app/tests/services/tutor/test_utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
from fastapi import HTTPException, UploadFile
from qdrant_client.models import ScoredPoint

from src.app.services.tutor.utils import (
from src.app.shared.utils.utils import (
build_system_message,
extract_doc_info,
get_file_content,
Expand Down
Empty file added src/app/tutor/__init__.py
Empty file.
Empty file added src/app/tutor/api/__init__.py
Empty file.
Original file line number Diff line number Diff line change
Expand Up @@ -11,16 +11,17 @@
UploadFile,
)

from src.app.shared.utils.dependencies import get_settings
from src.app.core.config import Settings
from src.app.models.search import EnhancedSearchQuery
from src.app.services.abst_chat import get_chat_service
from src.app.services.data_collection import get_data_collection_service
from src.app.services.exceptions import NoResultsError
from src.app.services.search import SearchService, get_search_service
from src.app.services.search_helpers import search_multi_inputs
from src.app.services.tutor.agents import TEMPLATES
from src.app.services.tutor.models import (
from src.app.shared.infra.abst_chat import get_chat_service
from src.app.shared.utils.dependencies import get_settings
from src.app.shared.utils.utils import get_files_content
from src.app.tutor.service.agents import TEMPLATES
from src.app.tutor.service.models import (
ExtractorOutputList,
SummariesList,
SyllabusFeedback,
Expand All @@ -30,13 +31,12 @@
TutorSearchResponse,
TutorSyllabusRequest,
)
from src.app.services.tutor.prompts import (
from src.app.tutor.service.prompts import (
extractor_system_prompt,
extractor_user_prompt,
summaries_schema,
)
from src.app.services.tutor.tutor import tutor_manager
from src.app.services.tutor.utils import get_files_content
from src.app.tutor.service.tutor import tutor_manager
from src.app.utils.logger import logger as utils_logger

logger = utils_logger(__name__)
Expand Down
Empty file.
File renamed without changes.
Empty file.
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,8 @@
from langchain_core.output_parsers import StrOutputParser
from langchain_core.prompts import ChatPromptTemplate

from src.app.services.tutor.models import MessageWithResources, SyllabusResponseAgent
from src.app.services.tutor.utils import build_system_message
from src.app.shared.utils.utils import build_system_message
from src.app.tutor.service.models import MessageWithResources, SyllabusResponseAgent
from src.app.utils.logger import logger as utils_logger

logger = utils_logger(__name__)
Expand All @@ -20,7 +20,7 @@ def get_disciplinary_skills():
global _DISCIPLINARY_SKILLS
if _DISCIPLINARY_SKILLS is None:
try:
path = Path(__file__).parent / "disciplinary_skills.json"
path = Path(__file__).parent.parent / "domain" / "disciplinary_skills.json"
with open(path, "r", encoding="utf-8") as f:
_DISCIPLINARY_SKILLS = {
d["code_rncp"]: d["skills"] for d in json.load(f)["disciplines"]
Expand All @@ -32,7 +32,7 @@ def get_disciplinary_skills():


# TODO: add template file move this to utils
TEMPLATES = {"template0": Path("src/app/services/tutor/template.md").read_text()}
TEMPLATES = {"template0": Path("src/app/tutor/domain/template.md").read_text()}


class TutorChatAgent:
Expand Down
File renamed without changes.
File renamed without changes.
Loading
Loading