feat(api): add chat functionality (Sprint 3)

Implement Sprint 3: Chat Functionality

- Add ChatService with send_message and get_history methods
- Add POST /api/v1/notebooks/{id}/chat - Send message
- Add GET /api/v1/notebooks/{id}/chat/history - Get chat history
- Add ChatRequest model (message, include_references)
- Add ChatResponse model (message, sources[], timestamp)
- Add ChatMessage model (id, role, content, timestamp, sources)
- Add SourceReference model (source_id, title, snippet)
- Integrate chat router with main app

Features:
- Send messages to notebook chat
- Get AI responses with source references
- Retrieve chat history
- Support for citations in responses

Tests:
- 14 unit tests for ChatService
- 11 integration tests for chat API
- 25/25 tests passing

Related: Sprint 3 - Chat Functionality
This commit is contained in:
Luca Sacchi Ricciardi
2026-04-06 01:48:19 +02:00
parent 3991ffdd7f
commit 081f3f0d89
8 changed files with 1225 additions and 1 deletions

View File

@@ -418,3 +418,129 @@ class HealthStatus(BaseModel):
description="Service name",
examples=["notebooklm-agent-api"],
)
class SourceReference(BaseModel):
"""Source reference in chat response.
Attributes:
source_id: The source ID.
title: The source title.
snippet: Relevant text snippet from the source.
"""
model_config = ConfigDict(
json_schema_extra={
"example": {
"source_id": "550e8400-e29b-41d4-a716-446655440001",
"title": "Example Article",
"snippet": "Key information from the source...",
}
}
)
source_id: str = Field(
...,
description="The source ID",
examples=["550e8400-e29b-41d4-a716-446655440001"],
)
title: str = Field(
...,
description="The source title",
examples=["Example Article"],
)
snippet: str | None = Field(
None,
description="Relevant text snippet from the source",
examples=["Key information from the source..."],
)
class ChatResponse(BaseModel):
"""Chat response model.
Attributes:
message: The assistant's response message.
sources: List of source references used in the response.
timestamp: Response timestamp.
"""
model_config = ConfigDict(
json_schema_extra={
"example": {
"message": "Based on the sources, here are the key points...",
"sources": [
{
"source_id": "550e8400-e29b-41d4-a716-446655440001",
"title": "Example Article",
"snippet": "Key information...",
}
],
"timestamp": "2026-04-06T10:30:00Z",
}
}
)
message: str = Field(
...,
description="The assistant's response message",
examples=["Based on the sources, here are the key points..."],
)
sources: list[SourceReference] = Field(
default_factory=list,
description="List of source references used in the response",
)
timestamp: datetime = Field(
...,
description="Response timestamp",
examples=["2026-04-06T10:30:00Z"],
)
class ChatMessage(BaseModel):
"""Chat message model.
Attributes:
id: Unique message identifier.
role: Message role (user or assistant).
content: Message content.
timestamp: Message timestamp.
sources: Source references (for assistant messages).
"""
model_config = ConfigDict(
json_schema_extra={
"example": {
"id": "550e8400-e29b-41d4-a716-446655440002",
"role": "assistant",
"content": "Based on the sources...",
"timestamp": "2026-04-06T10:30:00Z",
"sources": [],
}
}
)
id: str = Field(
...,
description="Unique message identifier",
examples=["550e8400-e29b-41d4-a716-446655440002"],
)
role: str = Field(
...,
description="Message role (user or assistant)",
examples=["user", "assistant"],
)
content: str = Field(
...,
description="Message content",
examples=["What are the key points?"],
)
timestamp: datetime = Field(
...,
description="Message timestamp",
examples=["2026-04-06T10:30:00Z"],
)
sources: list[SourceReference] | None = Field(
None,
description="Source references (for assistant messages)",
)