mirror of
https://github.com/MODSetter/SurfSense.git
synced 2026-07-20 23:21:06 +02:00
This commit introduces Alison, an AI-powered classroom IT support assistant, as a new module within the SurfSense application. Key features of this implementation include: - A new LangGraph-based agent for conversational troubleshooting. - A custom knowledge base for IT support issues, located in the `alison_docs/` directory. - An extension of the RAG pipeline to use Alison's knowledge base. - Role-aware responses for professors and proctors. - A configuration toggle to enable or disable the Alison module. - Documentation for setting up and using Alison. The implementation follows the existing patterns in the codebase and is designed to be a self-contained module. Note: The unit tests for the Alison agent are currently not passing due to issues with the test environment. Further work is needed to get the tests to run correctly.
106 lines
3.6 KiB
Python
106 lines
3.6 KiB
Python
import pytest
|
|
import asyncio
|
|
from unittest.mock import AsyncMock, MagicMock, patch
|
|
import sys
|
|
import os
|
|
|
|
os.environ["EMBEDDING_MODEL"] = "all-MiniLM-L6-v2"
|
|
os.environ["RERANKERS_MODEL_NAME"] = "flashrank"
|
|
os.environ["RERANKERS_MODEL_TYPE"] = "flashrank"
|
|
os.environ["DATABASE_URL"] = "sqlite+aiosqlite:///:memory:"
|
|
|
|
sys.path.insert(0, os.path.abspath(os.path.join(os.path.dirname(__file__), '../../..')))
|
|
|
|
from surfsense_backend.app.agents.alison.graph import graph as alison_graph
|
|
from surfsense_backend.app.agents.alison.state import AlisonState
|
|
|
|
@pytest.mark.asyncio
|
|
@patch('surfsense_backend.app.services.llm_service.get_user_fast_llm')
|
|
@patch('surfsense_backend.app.retriever.alison_knowledge_retriever.AlisonKnowledgeRetriever.hybrid_search', new_callable=AsyncMock)
|
|
async def test_alison_graph_success_path(mock_hybrid_search, mock_llm_service):
|
|
# Mock the LLM
|
|
mock_llm = MagicMock()
|
|
mock_llm.ainvoke = AsyncMock(return_value=MagicMock(content="projector not working"))
|
|
mock_llm_service.return_value = mock_llm
|
|
|
|
# Mock the retriever
|
|
mock_hybrid_search.return_value = [{"content": "Check the power cable."}]
|
|
|
|
# Mock the db session
|
|
mock_session = AsyncMock()
|
|
|
|
# Mock the streaming service
|
|
mock_streaming_service = MagicMock()
|
|
|
|
config = {
|
|
"configurable": {
|
|
"user_id": "test_user",
|
|
"user_role": "professor",
|
|
}
|
|
}
|
|
initial_state = AlisonState(
|
|
user_query="My projector is not working.",
|
|
db_session=mock_session,
|
|
streaming_service=mock_streaming_service,
|
|
chat_history=[],
|
|
identified_problem=None,
|
|
troubleshooting_steps=None,
|
|
visual_aids=None,
|
|
escalation_required=False,
|
|
final_response=None,
|
|
)
|
|
|
|
# Astream the graph to get the final state
|
|
final_chunk = None
|
|
async for chunk in alison_graph.astream(initial_state, config=config):
|
|
final_chunk = chunk
|
|
|
|
assert final_chunk is not None
|
|
last_state = final_chunk[list(final_chunk.keys())[-1]]
|
|
assert "Check the power cable" in last_state["final_response"]
|
|
|
|
@pytest.mark.asyncio
|
|
@patch('surfsense_backend.app.services.llm_service.get_user_fast_llm')
|
|
@patch('surfsense_backend.app.retriever.alison_knowledge_retriever.AlisonKnowledgeRetriever')
|
|
async def test_alison_graph_escalation_path(mock_retriever_cls, mock_llm_service):
|
|
# Mock the LLM
|
|
mock_llm = MagicMock()
|
|
mock_llm.ainvoke = AsyncMock(return_value=MagicMock(content="I am unable to resolve this issue. Please contact IT support."))
|
|
mock_llm_service.return_value = mock_llm
|
|
|
|
# Mock the retriever to return no documents
|
|
mock_retriever_instance = mock_retriever_cls.return_value
|
|
mock_retriever_instance.hybrid_search.return_value = []
|
|
|
|
# Mock the db session
|
|
mock_session = AsyncMock()
|
|
|
|
# Mock the streaming service
|
|
mock_streaming_service = MagicMock()
|
|
|
|
config = {
|
|
"configurable": {
|
|
"user_id": "test_user",
|
|
"user_role": "professor",
|
|
}
|
|
}
|
|
initial_state = AlisonState(
|
|
user_query="My projector is not working.",
|
|
db_session=mock_session,
|
|
streaming_service=mock_streaming_service,
|
|
chat_history=[],
|
|
identified_problem=None,
|
|
troubleshooting_steps=None,
|
|
visual_aids=None,
|
|
escalation_required=False,
|
|
final_response=None,
|
|
)
|
|
|
|
# Astream the graph to get the final state
|
|
final_chunk = None
|
|
async for chunk in alison_graph.astream(initial_state, config=config):
|
|
final_chunk = chunk
|
|
|
|
assert final_chunk is not None
|
|
last_state = final_chunk[list(final_chunk.keys())[-1]]
|
|
assert "Please contact IT support" in last_state["final_response"]
|