mirror of
https://github.com/danswer-ai/danswer.git
synced 2025-09-29 13:25:50 +02:00
Add start/end date ability for query history as CSV endpoint (#3211)
This commit is contained in:
@@ -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,
|
||||||
)
|
)
|
||||||
|
@@ -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"]
|
||||||
]
|
]
|
||||||
|
@@ -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):
|
||||||
|
@@ -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
|
||||||
|
Reference in New Issue
Block a user