mirror of
https://github.com/danswer-ai/danswer.git
synced 2025-10-10 13:15:18 +02:00
Extend query history API
This commit is contained in:
@@ -92,10 +92,12 @@ class ChatSessionMinimal(BaseModel):
|
|||||||
name: str | None
|
name: str | None
|
||||||
first_user_message: str
|
first_user_message: str
|
||||||
first_ai_message: str
|
first_ai_message: str
|
||||||
persona_name: str | None
|
assistant_id: int | None
|
||||||
|
assistant_name: str | None
|
||||||
time_created: datetime
|
time_created: datetime
|
||||||
feedback_type: QAFeedbackType | Literal["mixed"] | None
|
feedback_type: QAFeedbackType | Literal["mixed"] | None
|
||||||
flow_type: SessionType
|
flow_type: SessionType
|
||||||
|
conversation_length: int
|
||||||
|
|
||||||
|
|
||||||
class ChatSessionSnapshot(BaseModel):
|
class ChatSessionSnapshot(BaseModel):
|
||||||
@@ -103,7 +105,8 @@ class ChatSessionSnapshot(BaseModel):
|
|||||||
user_email: str
|
user_email: str
|
||||||
name: str | None
|
name: str | None
|
||||||
messages: list[MessageSnapshot]
|
messages: list[MessageSnapshot]
|
||||||
persona_name: str | None
|
assistant_id: int | None
|
||||||
|
assistant_name: str | None
|
||||||
time_created: datetime
|
time_created: datetime
|
||||||
flow_type: SessionType
|
flow_type: SessionType
|
||||||
|
|
||||||
@@ -146,7 +149,7 @@ class QuestionAnswerPairSnapshot(BaseModel):
|
|||||||
retrieved_documents=ai_message.documents,
|
retrieved_documents=ai_message.documents,
|
||||||
feedback_type=ai_message.feedback_type,
|
feedback_type=ai_message.feedback_type,
|
||||||
feedback_text=ai_message.feedback_text,
|
feedback_text=ai_message.feedback_text,
|
||||||
persona_name=chat_session_snapshot.persona_name,
|
persona_name=chat_session_snapshot.assistant_name,
|
||||||
user_email=get_display_email(chat_session_snapshot.user_email),
|
user_email=get_display_email(chat_session_snapshot.user_email),
|
||||||
time_created=user_message.time_created,
|
time_created=user_message.time_created,
|
||||||
flow_type=chat_session_snapshot.flow_type,
|
flow_type=chat_session_snapshot.flow_type,
|
||||||
@@ -257,12 +260,20 @@ def fetch_and_process_chat_session_history_minimal(
|
|||||||
name=chat_session.description,
|
name=chat_session.description,
|
||||||
first_user_message=first_user_message,
|
first_user_message=first_user_message,
|
||||||
first_ai_message=first_ai_message,
|
first_ai_message=first_ai_message,
|
||||||
persona_name=chat_session.persona.name
|
assistant_id=chat_session.persona_id,
|
||||||
if chat_session.persona
|
assistant_name=(
|
||||||
else None,
|
chat_session.persona.name if chat_session.persona else None
|
||||||
|
),
|
||||||
time_created=chat_session.time_created,
|
time_created=chat_session.time_created,
|
||||||
feedback_type=feedback_type,
|
feedback_type=feedback_type,
|
||||||
flow_type=flow_type,
|
flow_type=flow_type,
|
||||||
|
conversation_length=len(
|
||||||
|
[
|
||||||
|
m
|
||||||
|
for m in chat_session.messages
|
||||||
|
if m.message_type != MessageType.SYSTEM
|
||||||
|
]
|
||||||
|
),
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -327,7 +338,8 @@ def snapshot_from_chat_session(
|
|||||||
for message in messages
|
for message in messages
|
||||||
if message.message_type != MessageType.SYSTEM
|
if message.message_type != MessageType.SYSTEM
|
||||||
],
|
],
|
||||||
persona_name=chat_session.persona.name if chat_session.persona else None,
|
assistant_id=chat_session.persona_id,
|
||||||
|
assistant_name=chat_session.persona.name if chat_session.persona else None,
|
||||||
time_created=chat_session.time_created,
|
time_created=chat_session.time_created,
|
||||||
flow_type=flow_type,
|
flow_type=flow_type,
|
||||||
)
|
)
|
||||||
|
@@ -0,0 +1,119 @@
|
|||||||
|
from datetime import datetime
|
||||||
|
from datetime import timedelta
|
||||||
|
from datetime import timezone
|
||||||
|
|
||||||
|
import requests
|
||||||
|
|
||||||
|
from danswer.configs.constants import QAFeedbackType
|
||||||
|
from danswer.configs.constants import SessionType
|
||||||
|
from tests.integration.common_utils.constants import API_SERVER_URL
|
||||||
|
from tests.integration.common_utils.managers.api_key import APIKeyManager
|
||||||
|
from tests.integration.common_utils.managers.cc_pair import CCPairManager
|
||||||
|
from tests.integration.common_utils.managers.chat import ChatSessionManager
|
||||||
|
from tests.integration.common_utils.managers.document import DocumentManager
|
||||||
|
from tests.integration.common_utils.managers.llm_provider import LLMProviderManager
|
||||||
|
from tests.integration.common_utils.managers.user import UserManager
|
||||||
|
from tests.integration.common_utils.test_models import DATestUser
|
||||||
|
|
||||||
|
|
||||||
|
def test_query_history_endpoints(reset: None) -> None:
|
||||||
|
# Create admin user and required resources
|
||||||
|
admin_user: DATestUser = UserManager.create(name="admin_user")
|
||||||
|
cc_pair = CCPairManager.create_from_scratch(user_performing_action=admin_user)
|
||||||
|
api_key = APIKeyManager.create(user_performing_action=admin_user)
|
||||||
|
LLMProviderManager.create(user_performing_action=admin_user)
|
||||||
|
|
||||||
|
# Seed a document
|
||||||
|
cc_pair.documents = []
|
||||||
|
cc_pair.documents.append(
|
||||||
|
DocumentManager.seed_doc_with_content(
|
||||||
|
cc_pair=cc_pair,
|
||||||
|
content="The company's revenue in Q1 was $1M",
|
||||||
|
api_key=api_key,
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
# Create chat session and send a message
|
||||||
|
chat_session = ChatSessionManager.create(
|
||||||
|
persona_id=0,
|
||||||
|
description="Test chat session",
|
||||||
|
user_performing_action=admin_user,
|
||||||
|
)
|
||||||
|
|
||||||
|
ChatSessionManager.send_message(
|
||||||
|
chat_session_id=chat_session.id,
|
||||||
|
message="What was the Q1 revenue?",
|
||||||
|
user_performing_action=admin_user,
|
||||||
|
)
|
||||||
|
|
||||||
|
# Test get chat session history endpoint
|
||||||
|
end_time = datetime.now(tz=timezone.utc)
|
||||||
|
start_time = end_time - timedelta(days=1)
|
||||||
|
|
||||||
|
response = requests.get(
|
||||||
|
f"{API_SERVER_URL}/admin/chat-session-history",
|
||||||
|
params={
|
||||||
|
"start": start_time.isoformat(),
|
||||||
|
"end": end_time.isoformat(),
|
||||||
|
},
|
||||||
|
headers=admin_user.headers,
|
||||||
|
)
|
||||||
|
assert response.status_code == 200
|
||||||
|
history_response = response.json()
|
||||||
|
|
||||||
|
# Verify we got back the one chat session we created
|
||||||
|
assert len(history_response) == 1
|
||||||
|
|
||||||
|
# Verify the first chat session details
|
||||||
|
first_session = history_response[0]
|
||||||
|
first_chat_id = first_session["id"]
|
||||||
|
assert first_session["user_email"] == admin_user.email
|
||||||
|
assert first_session["name"] == "Test chat session"
|
||||||
|
assert first_session["first_user_message"] == "What was the Q1 revenue?"
|
||||||
|
assert first_session["first_ai_message"] is not None
|
||||||
|
assert first_session["assistant_id"] == 0
|
||||||
|
assert first_session["feedback_type"] is None
|
||||||
|
assert first_session["flow_type"] == SessionType.CHAT.value
|
||||||
|
assert first_session["conversation_length"] == 2 # User message + AI response
|
||||||
|
|
||||||
|
# Test get specific chat session endpoint
|
||||||
|
response = requests.get(
|
||||||
|
f"{API_SERVER_URL}/admin/chat-session-history/{first_chat_id}",
|
||||||
|
headers=admin_user.headers,
|
||||||
|
)
|
||||||
|
assert response.status_code == 200
|
||||||
|
session_details = response.json()
|
||||||
|
|
||||||
|
# Verify the session details
|
||||||
|
assert session_details["id"] == first_chat_id
|
||||||
|
assert len(session_details["messages"]) > 0
|
||||||
|
assert session_details["flow_type"] == SessionType.CHAT.value
|
||||||
|
|
||||||
|
# Test CSV export endpoint
|
||||||
|
response = requests.get(
|
||||||
|
f"{API_SERVER_URL}/admin/query-history-csv",
|
||||||
|
headers=admin_user.headers,
|
||||||
|
)
|
||||||
|
assert response.status_code == 200
|
||||||
|
assert response.headers["Content-Type"] == "text/csv; charset=utf-8"
|
||||||
|
assert "Content-Disposition" in response.headers
|
||||||
|
|
||||||
|
# Verify CSV content
|
||||||
|
csv_content = response.content.decode()
|
||||||
|
assert "chat_session_id" in csv_content
|
||||||
|
assert "user_message" in csv_content
|
||||||
|
assert "ai_response" in csv_content
|
||||||
|
|
||||||
|
# Test filtering by feedback
|
||||||
|
response = requests.get(
|
||||||
|
f"{API_SERVER_URL}/admin/chat-session-history",
|
||||||
|
params={
|
||||||
|
"feedback_type": QAFeedbackType.LIKE.value,
|
||||||
|
"start": start_time.isoformat(),
|
||||||
|
"end": end_time.isoformat(),
|
||||||
|
},
|
||||||
|
headers=admin_user.headers,
|
||||||
|
)
|
||||||
|
assert response.status_code == 200
|
||||||
|
history_response = response.json()
|
||||||
|
assert len(history_response) == 0
|
@@ -56,7 +56,7 @@ function QueryHistoryTableRow({
|
|||||||
<FeedbackBadge feedback={chatSessionMinimal.feedback_type} />
|
<FeedbackBadge feedback={chatSessionMinimal.feedback_type} />
|
||||||
</TableCell>
|
</TableCell>
|
||||||
<TableCell>{chatSessionMinimal.user_email || "-"}</TableCell>
|
<TableCell>{chatSessionMinimal.user_email || "-"}</TableCell>
|
||||||
<TableCell>{chatSessionMinimal.persona_name || "Unknown"}</TableCell>
|
<TableCell>{chatSessionMinimal.assistant_name || "Unknown"}</TableCell>
|
||||||
<TableCell>
|
<TableCell>
|
||||||
{timestampToReadableDate(chatSessionMinimal.time_created)}
|
{timestampToReadableDate(chatSessionMinimal.time_created)}
|
||||||
</TableCell>
|
</TableCell>
|
||||||
|
@@ -38,7 +38,8 @@ export interface ChatSessionSnapshot {
|
|||||||
user_email: string | null;
|
user_email: string | null;
|
||||||
name: string | null;
|
name: string | null;
|
||||||
messages: MessageSnapshot[];
|
messages: MessageSnapshot[];
|
||||||
persona_name: string | null;
|
assistant_id: number | null;
|
||||||
|
assistant_name: string | null;
|
||||||
time_created: string;
|
time_created: string;
|
||||||
flow_type: SessionType;
|
flow_type: SessionType;
|
||||||
}
|
}
|
||||||
@@ -49,10 +50,12 @@ export interface ChatSessionMinimal {
|
|||||||
name: string | null;
|
name: string | null;
|
||||||
first_user_message: string;
|
first_user_message: string;
|
||||||
first_ai_message: string;
|
first_ai_message: string;
|
||||||
persona_name: string | null;
|
assistant_id: number | null;
|
||||||
|
assistant_name: string | null;
|
||||||
time_created: string;
|
time_created: string;
|
||||||
feedback_type: Feedback | "mixed" | null;
|
feedback_type: Feedback | "mixed" | null;
|
||||||
flow_type: SessionType;
|
flow_type: SessionType;
|
||||||
|
conversation_length: number;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface UsageReport {
|
export interface UsageReport {
|
||||||
|
Reference in New Issue
Block a user