Add start/end date ability for query history as CSV endpoint (#3211)

This commit is contained in:
Chris Weaver
2024-11-22 10:29:13 -08:00
committed by GitHub
parent 67bfcabbc5
commit 129c8f8faf
4 changed files with 81 additions and 28 deletions

View File

@@ -427,12 +427,14 @@ def get_chat_session_admin(
@router.get("/admin/query-history-csv") @router.get("/admin/query-history-csv")
def get_query_history_as_csv( def get_query_history_as_csv(
_: User | None = Depends(current_admin_user), _: User | None = Depends(current_admin_user),
start: datetime | None = None,
end: datetime | None = None,
db_session: Session = Depends(get_session), db_session: Session = Depends(get_session),
) -> StreamingResponse: ) -> StreamingResponse:
complete_chat_session_history = fetch_and_process_chat_session_history( complete_chat_session_history = fetch_and_process_chat_session_history(
db_session=db_session, db_session=db_session,
start=datetime.fromtimestamp(0, tz=timezone.utc), start=start or datetime.fromtimestamp(0, tz=timezone.utc),
end=datetime.now(tz=timezone.utc), end=end or datetime.now(tz=timezone.utc),
feedback_type=None, feedback_type=None,
limit=None, limit=None,
) )

View File

@@ -142,7 +142,7 @@ class ChatSessionManager:
user_performing_action: DATestUser | None = None, user_performing_action: DATestUser | None = None,
) -> list[DATestChatMessage]: ) -> list[DATestChatMessage]:
response = requests.get( response = requests.get(
f"{API_SERVER_URL}/chat/history/{chat_session.id}", f"{API_SERVER_URL}/chat/get-chat-session/{chat_session.id}",
headers=user_performing_action.headers headers=user_performing_action.headers
if user_performing_action if user_performing_action
else GENERAL_HEADERS, else GENERAL_HEADERS,
@@ -151,11 +151,10 @@ class ChatSessionManager:
return [ return [
DATestChatMessage( DATestChatMessage(
id=msg["id"], id=msg["message_id"],
chat_session_id=chat_session.id, chat_session_id=chat_session.id,
parent_message_id=msg.get("parent_message_id"), parent_message_id=msg.get("parent_message"),
message=msg["message"], message=msg["message"],
response=msg.get("response", ""),
) )
for msg in response.json() for msg in response.json()["messages"]
] ]

View File

@@ -136,11 +136,10 @@ class DATestChatSession(BaseModel):
class DATestChatMessage(BaseModel): class DATestChatMessage(BaseModel):
id: str | None = None id: int
chat_session_id: UUID chat_session_id: UUID
parent_message_id: str | None parent_message_id: int | None
message: str message: str
response: str
class StreamedResponse(BaseModel): class StreamedResponse(BaseModel):

View File

@@ -2,6 +2,7 @@ from datetime import datetime
from datetime import timedelta from datetime import timedelta
from datetime import timezone from datetime import timezone
import pytest
import requests import requests
from danswer.configs.constants import QAFeedbackType from danswer.configs.constants import QAFeedbackType
@@ -16,7 +17,8 @@ from tests.integration.common_utils.managers.user import UserManager
from tests.integration.common_utils.test_models import DATestUser from tests.integration.common_utils.test_models import DATestUser
def test_query_history_endpoints(reset: None) -> None: @pytest.fixture
def setup_chat_session(reset: None) -> tuple[DATestUser, str]:
# Create admin user and required resources # Create admin user and required resources
admin_user: DATestUser = UserManager.create(name="admin_user") admin_user: DATestUser = UserManager.create(name="admin_user")
cc_pair = CCPairManager.create_from_scratch(user_performing_action=admin_user) cc_pair = CCPairManager.create_from_scratch(user_performing_action=admin_user)
@@ -46,16 +48,29 @@ def test_query_history_endpoints(reset: None) -> None:
user_performing_action=admin_user, user_performing_action=admin_user,
) )
# Test get chat session history endpoint messages = ChatSessionManager.get_chat_history(
end_time = datetime.now(tz=timezone.utc) chat_session=chat_session,
start_time = end_time - timedelta(days=1) user_performing_action=admin_user,
)
# Add another message to the chat session
ChatSessionManager.send_message(
chat_session_id=chat_session.id,
message="What about Q2 revenue?",
user_performing_action=admin_user,
parent_message_id=messages[-1].id,
)
return admin_user, str(chat_session.id)
def test_chat_history_endpoints(
reset: None, setup_chat_session: tuple[DATestUser, str]
) -> None:
admin_user, first_chat_id = setup_chat_session
response = requests.get( response = requests.get(
f"{API_SERVER_URL}/admin/chat-session-history", f"{API_SERVER_URL}/admin/chat-session-history",
params={
"start": start_time.isoformat(),
"end": end_time.isoformat(),
},
headers=admin_user.headers, headers=admin_user.headers,
) )
assert response.status_code == 200 assert response.status_code == 200
@@ -66,7 +81,6 @@ def test_query_history_endpoints(reset: None) -> None:
# Verify the first chat session details # Verify the first chat session details
first_session = history_response[0] first_session = history_response[0]
first_chat_id = first_session["id"]
assert first_session["user_email"] == admin_user.email assert first_session["user_email"] == admin_user.email
assert first_session["name"] == "Test chat session" assert first_session["name"] == "Test chat session"
assert first_session["first_user_message"] == "What was the Q1 revenue?" assert first_session["first_user_message"] == "What was the Q1 revenue?"
@@ -74,7 +88,22 @@ def test_query_history_endpoints(reset: None) -> None:
assert first_session["assistant_id"] == 0 assert first_session["assistant_id"] == 0
assert first_session["feedback_type"] is None assert first_session["feedback_type"] is None
assert first_session["flow_type"] == SessionType.CHAT.value assert first_session["flow_type"] == SessionType.CHAT.value
assert first_session["conversation_length"] == 2 # User message + AI response assert first_session["conversation_length"] == 4 # 2 User messages + 2 AI responses
# Test date filtering - should return no results
past_end = datetime.now(tz=timezone.utc) - timedelta(days=1)
past_start = past_end - timedelta(days=1)
response = requests.get(
f"{API_SERVER_URL}/admin/chat-session-history",
params={
"start": past_start.isoformat(),
"end": past_end.isoformat(),
},
headers=admin_user.headers,
)
assert response.status_code == 200
history_response = response.json()
assert len(history_response) == 0
# Test get specific chat session endpoint # Test get specific chat session endpoint
response = requests.get( response = requests.get(
@@ -89,7 +118,25 @@ def test_query_history_endpoints(reset: None) -> None:
assert len(session_details["messages"]) > 0 assert len(session_details["messages"]) > 0
assert session_details["flow_type"] == SessionType.CHAT.value assert session_details["flow_type"] == SessionType.CHAT.value
# Test CSV export endpoint # Test filtering by feedback
response = requests.get(
f"{API_SERVER_URL}/admin/chat-session-history",
params={
"feedback_type": QAFeedbackType.LIKE.value,
},
headers=admin_user.headers,
)
assert response.status_code == 200
history_response = response.json()
assert len(history_response) == 0
def test_chat_history_csv_export(
reset: None, setup_chat_session: tuple[DATestUser, str]
) -> None:
admin_user, _ = setup_chat_session
# Test CSV export endpoint with date filtering
response = requests.get( response = requests.get(
f"{API_SERVER_URL}/admin/query-history-csv", f"{API_SERVER_URL}/admin/query-history-csv",
headers=admin_user.headers, headers=admin_user.headers,
@@ -100,20 +147,26 @@ def test_query_history_endpoints(reset: None) -> None:
# Verify CSV content # Verify CSV content
csv_content = response.content.decode() csv_content = response.content.decode()
csv_lines = csv_content.strip().split("\n")
assert len(csv_lines) == 3 # Header + 2 QA pairs
assert "chat_session_id" in csv_content assert "chat_session_id" in csv_content
assert "user_message" in csv_content assert "user_message" in csv_content
assert "ai_response" in csv_content assert "ai_response" in csv_content
assert "What was the Q1 revenue?" in csv_content
assert "What about Q2 revenue?" in csv_content
# Test filtering by feedback # Test CSV export with date filtering - should return no results
past_end = datetime.now(tz=timezone.utc) - timedelta(days=1)
past_start = past_end - timedelta(days=1)
response = requests.get( response = requests.get(
f"{API_SERVER_URL}/admin/chat-session-history", f"{API_SERVER_URL}/admin/query-history-csv",
params={ params={
"feedback_type": QAFeedbackType.LIKE.value, "start": past_start.isoformat(),
"start": start_time.isoformat(), "end": past_end.isoformat(),
"end": end_time.isoformat(),
}, },
headers=admin_user.headers, headers=admin_user.headers,
) )
assert response.status_code == 200 assert response.status_code == 200
history_response = response.json() csv_content = response.content.decode()
assert len(history_response) == 0 csv_lines = csv_content.strip().split("\n")
assert len(csv_lines) == 1 # Only header, no data rows